package tm.gui;

import javax.media.opengl.GL;
import javax.media.opengl.GL2;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.GLEventListener;
import javax.media.opengl.fixedfunc.GLMatrixFunc;

import res.exceptions.RendererNotReadyException;
import res.graph.Edge;
import agents.TrafficLightAgent;

public class GridRoadRenderer implements GLEventListener {

    private static final int POINT_SIZE = 7;
    private static final int LINE_WIDTH = 3;
    
    private static final float[] edgeColorsRed   = new float[]{      0.0f,       0.0f, 1.0f,       1.0f, 1.0f};
    private static final float[] edgeColorsGreen = new float[]{148.0f/255, 210.0f/255, 1.0f, 140.0f/255, 0.0f};
    private static final float[] edgeColorsBlue  = new float[]{111.0f/255, 111.0f/255, 0.0f, 128.0f/255, 0.0f};

    private static final float[] lightColorsRed   = new float[]{      0.0f, 1.0f};
    private static final float[] lightColorsGreen = new float[]{148.0f/255, 0.0f};
    private static final float[] lightColorsBlue  = new float[]{111.0f/255, 0.0f};
    
    private static GridRoadRenderer instance = null;
    
    private Iterable<TrafficLightAgent> agents;
    private int columns;
    private int rows;
    private int cwidth;
    private int cheight;
    
    private GridRoadRenderer(Iterable<TrafficLightAgent> agents, int width, int height) {
    	this.agents = agents;
    	this.columns = width;
    	this.rows = height;
    }
    
    public static void initRenderer(Iterable<TrafficLightAgent> agents, int width, int height) {
    	instance = new GridRoadRenderer(agents, width, height);
    }
    
    public static GridRoadRenderer getInstance() {
    	if(instance == null)
    		throw new RendererNotReadyException();
    	
    	return instance;
    }
    
	@Override
	public void display(GLAutoDrawable drawable) {
		GL2 gl = drawable.getGL().getGL2();
		Edge edge;
		int agentstate = TrafficLightAgent.RED_STATE;
		int normwidth = (cwidth - 4*POINT_SIZE - 1) / (columns - 1);
		int normheight = (cheight - 4*POINT_SIZE - 1) / (rows - 1);
		int sy, sx, ty, tx;
		int s, t;
		int load, offset;
		
		gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);

		gl.glClear(GL.GL_COLOR_BUFFER_BIT);
		
	    for(TrafficLightAgent agent : agents) {
	    	edge = agent.getEdge();
	    	load = (int) Math.floor(5.0 * edge.getLoad() / edge.getWeight());
	    	if(load >= 5)
	    		load = 4;
	    	agentstate = 0;//agent.getState();
	    	s = edge.getSource().getOrd();
	    	t = edge.getTarget().getOrd();
	    	offset = s - t;
	    	
	    	sx = s % columns;
	    	sy = s / columns;
	    	tx = t % columns;
	    	ty = t / columns;
	    	
	    	System.out.println(String.format("ROWS %d SX %d TX %d SY %d TY %d", rows, sx, tx, sy, ty));
	    	
	    	gl.glColor3f(edgeColorsRed[load], edgeColorsGreen[load], edgeColorsBlue[load]);
	    	
		    gl.glBegin(GL.GL_LINES);
		    	if(offset == 1) {
			    	gl.glVertex2i(  sx*normwidth + 3 + POINT_SIZE, (rows-1-sy)*normheight + 3 + 2*POINT_SIZE);
			    	gl.glVertex2i(tx*normwidth - 2 + 3*POINT_SIZE, (rows-1-ty)*normheight + 3 + 2*POINT_SIZE);	
		    	} else if(offset == -1) {
			    	gl.glVertex2i(sx*normwidth + 2*POINT_SIZE + 5,   (rows-1-sy)*normheight + 6 + POINT_SIZE);
			    	gl.glVertex2i(  POINT_SIZE + tx*normwidth + 3,   (rows-1-ty)*normheight + 6 + POINT_SIZE);
		    	} else if(offset == columns) {
			    	gl.glVertex2i(2*POINT_SIZE + 3 + sx*normwidth, (rows-1-sy)*normheight + 5 + 2*POINT_SIZE);
			    	gl.glVertex2i(2*POINT_SIZE + 3 + tx*normwidth,   (rows-1-ty)*normheight + 3 + POINT_SIZE);	
		    	} else if(offset == -columns) {
			    	gl.glVertex2i(POINT_SIZE + 6 + sx*normwidth, (rows-1-sy)*normheight + 3 + POINT_SIZE);
			    	gl.glVertex2i(POINT_SIZE + 6 + tx*normwidth, (rows-1-ty)*normheight - 2 + 3*POINT_SIZE);
		    	}
		    gl.glEnd();
		    
	    	gl.glColor3f(lightColorsRed[agentstate], lightColorsGreen[agentstate], lightColorsBlue[agentstate]);
		    
		    gl.glBegin(GL.GL_POINTS);
		    	if(offset == 1) {
			    	gl.glVertex2i(3*POINT_SIZE + tx*normwidth + 1,   (rows-1-ty)*normheight + 3*POINT_SIZE + 1);	
		    	} else if(offset == -1) {
			    	gl.glVertex2i(tx*normwidth + POINT_SIZE - 1,   (rows-1-ty)*normheight + 6);
		    	} else if(offset == columns) {
			    	gl.glVertex2i(3*POINT_SIZE + 1 + tx*normwidth, (rows-1-ty)*normheight + POINT_SIZE - 1);	
		    	} else if(offset == -columns) {
			    	gl.glVertex2i(tx*normwidth + 6,   (rows-1-ty)*normheight + 3*POINT_SIZE + 1);
		    	}
	    	gl.glEnd();
	    }
	    	
	    drawVertices(gl);
	}

	private void drawVertices(GL2 gl) {		
		if(cwidth >= 7 && cheight >= 7) {
			int normwidth = (cwidth - 4*POINT_SIZE) / (columns - 1);
			int normheight = (cheight - 4*POINT_SIZE) / (rows - 1);

			gl.glColor3ui(255, 255, 255);
			gl.glBegin(GL.GL_POINTS);
			for(int i = 0; i < columns; i++) {
				for(int j = 0; j < rows; j++) {
					gl.glVertex2i(2*POINT_SIZE + i*normwidth, 2*POINT_SIZE + j*normheight);
				}
			}
			gl.glEnd();
		}
	}

	@Override
	public void dispose(GLAutoDrawable drawable) {}

	@Override
	public void init(GLAutoDrawable drawable) {
		GL2 gl = drawable.getGL().getGL2();
		
		this.cwidth = drawable.getWidth();
		this.cheight = drawable.getHeight();
		
		gl.glLineWidth(LINE_WIDTH);
		gl.glPointSize(POINT_SIZE);
		
		gl.glClearColor(1, 1, 1, 1);
		gl.glClear(GL.GL_COLOR_BUFFER_BIT);
		
		gl.glMatrixMode(GLMatrixFunc.GL_MODELVIEW);
		gl.glLoadIdentity();
		
		gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
		gl.glLoadIdentity();
		gl.glOrthof(0.0f, cwidth, 0.0f, cheight, -1.0f, 1.0f);

    	drawVertices(gl);
		
		System.out.println("init");
	}

	@Override
	public void reshape(GLAutoDrawable drawable, int x, int y, int width,
			int height) {
		GL2 gl = drawable.getGL().getGL2();

		cwidth = width-x;
		cheight = height-y;
		
		gl.glMatrixMode(GLMatrixFunc.GL_PROJECTION);
		gl.glLoadIdentity();
		gl.glOrthof(0.0f, cwidth, 0.0f, cheight, -1.0f, 1.0f);
	}

}
